package fr.miage.course7.app.view;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.List;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.TreeSet;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

import fr.miage.course7.app.controller.Controller;
import fr.miage.course7.app.model.Participant;
import fr.miage.course7.app.model.Transmission;

/**
 * Classe qui crée la vue.
 * @author Jean-Yannick TILIN
 * @author Alexandre JAHAN
 *
 */
public class Fenetre extends JFrame {

    private Controller control;
    private List listeDate;
    private ArrayList<Integer> classement;
    private HashMap<Integer, Color> lesCouleurs;
    private HashMap<Integer, Participant> lesParticipants;
    private TreeSet<Transmission> lesTransmissions;
    private final Panneau pan;
    private final JButton butt;
    private static final long serialVersionUID = 1L;

    /**
     * Constructeur de la classe.
     * @param controlleur controlleur de l'application
     */
    public Fenetre(final Controller controlleur) {
        this.control = controlleur;
        int width = 1080;
        int height = 500;
        lesCouleurs = new HashMap<Integer, Color>();
        lesCouleurs.put(1, Color.red);
        lesCouleurs.put(2, Color.blue);
        lesCouleurs.put(3, Color.green);
        lesCouleurs.put(4, Color.yellow);

        this.setResizable(false);
        this.setTitle("Courses Maritimes");
        this.setSize(width, height);
        this.setBackground(Color.white);
        this.setLocationRelativeTo(null);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pan = new Panneau(width, height);
        butt = new JButton("Rafraîchir");
        butt.addActionListener(new ButtonListener(this));

        this.setLayout(new BorderLayout());
        this.add(pan, BorderLayout.CENTER);
        JPanel droite = new JPanel(new BorderLayout());
        listeDate = new List();
        listeDate.addItemListener(new RafraichirItemListener(this));


        // Recuperation de toutes les coordonnees
        lesParticipants = control.getCourse().getParticipants();
        if (!lesParticipants.isEmpty()){
            lesTransmissions = lesParticipants.get(1).getTransmissions();
            for (Transmission transmission : lesTransmissions){
                listeDate.add(transmission.getDate().get(Calendar.DATE) + "/" + ((transmission.getDate().get(Calendar.MONTH) != 0)?transmission.getDate().get(Calendar.MONTH):"12") + "/" + transmission.getDate().get(Calendar.YEAR));
            }
        }
        droite.add(butt, BorderLayout.NORTH);
        droite.add(listeDate, BorderLayout.CENTER);
        this.add(droite, BorderLayout.EAST);

        this.setVisible(true);
    }

    /**
     * Méthode qui permet de rafraichir la fenetre d'affichage.
     */
    public void rafraichir() {
        int x, y;
        pan.clear();
        // Remplissage de la liste drawable
        for (Iterator<Participant> iter = control.getCourse().getParticipants().values().iterator(); iter.hasNext();) {
            Participant participant = iter.next();
            TreeSet<Transmission> listeCoordonnees = participant.getTransmissions();
            Iterator<Transmission> iterTransmission = listeCoordonnees.iterator();

            Transmission iterBack = iterTransmission.next();
            Transmission iterCourant = null;

            int cpt = 0;
            while (iterTransmission.hasNext() 
                   && (cpt < listeDate.getSelectedIndex()
                   || listeDate.getSelectedIndex() == -1)) {
                iterCourant = iterTransmission.next();
                // Si la distance est supérieure à 120
                // cela veux dire qu'on sort de la carte par l'un des côtés
                if (Math.abs((iterBack.getPosition().getLon() - iterCourant.getPosition().getLon())) > 120){
                    int diff = 0;
                    if (iterCourant.getPosition().getLon() > 0) {
                        diff = -360 + iterCourant.getPosition().getLon();
                        float coeffDirect = -(float) (iterCourant.getPosition().getLat() - iterBack.getPosition().getLat()) / (float) (diff - iterBack.getPosition().getLon());
                        int nouvLat = (int) (iterBack.getPosition().getLat() + (-180 - diff) * coeffDirect);
                        pan.addDrawable(new LineDrawable(lesCouleurs.get(Integer.parseInt( participant.getIdentifiant() + "" )), 
                                                                        ajusteLong(iterBack.getPosition().getLon()),
                                                                        ajusteLat(iterBack.getPosition().getLat()), 
                                                                        ajusteLong(-180), 
                                                                        ajusteLat(nouvLat)
                                                                        )
                                                        );
                        pan.addDrawable(new LineDrawable(lesCouleurs.get(Integer.parseInt( participant.getIdentifiant() + "" )), 
                                                                        ajusteLong(180),
                                                                        ajusteLat(nouvLat), 
                                                                        ajusteLong(iterCourant.getPosition().getLon()), 
                                                                        ajusteLat(iterCourant.getPosition().getLat())
                                                                        )
                                                        );
                    } else {
                        diff = 360+iterCourant.getPosition().getLon();
                        float coeffDirect = -(float) (iterCourant.getPosition().getLat() - iterBack.getPosition().getLat()) / (float) (diff - iterBack.getPosition().getLon());
                        int nouvLat = (int) (iterBack.getPosition().getLat() + (180 - diff) * coeffDirect);
                        pan.addDrawable(new LineDrawable(lesCouleurs.get(Integer.parseInt( participant.getIdentifiant() + "" )), 
                                                                        ajusteLong(iterBack.getPosition().getLon()),
                                                                        ajusteLat(iterBack.getPosition().getLat()), 
                                                                        ajusteLong(180), 
                                                                        ajusteLat(nouvLat)
                                                                        )
                                                        );
                        pan.addDrawable(new LineDrawable(lesCouleurs.get(Integer.parseInt( participant.getIdentifiant() + "" )), 
                                                                        ajusteLong(-180),
                                                                        ajusteLat(nouvLat), 
                                                                        ajusteLong(iterCourant.getPosition().getLon()), 
                                                                        ajusteLat(iterCourant.getPosition().getLat())
                                                                        )
                                                        );
                    }
                    iterBack = iterCourant;
                    cpt++;
                } else {
                    pan.addDrawable(new LineDrawable(lesCouleurs.get(Integer.parseInt( participant.getIdentifiant() + "" )), ajusteLong(iterBack.getPosition().getLon()), ajusteLat(iterBack.getPosition().getLat()), ajusteLong(iterCourant.getPosition().getLon()), ajusteLat(iterCourant.getPosition().getLat())));
                    iterBack = iterCourant;
                    cpt++;
                }
            }
            // coordonnées du bateau
            if (listeDate.getSelectedIndex() != 0) {
                x = ajusteLong(iterCourant.getPosition().getLon());
                y = ajusteLat(iterCourant.getPosition().getLat());
            }
            else {
            	x = ajusteLong(iterBack.getPosition().getLon());
                y = ajusteLat(iterBack.getPosition().getLat());
            }
            try {
                BufferedImage img = ImageIO.read(
                                        new File("./src/main/resources/bateau"
                                                 + participant.getIdentifiant()
                                                 + ".png"));
                pan.addDrawable(new ImageDrawable(img, x, y, 25, 25));
            } catch (IOException e) {
                e.printStackTrace();
            }
            
            // Ajout du classement en Antarctique
            pan.addDrawable(new StringDrawable("CLASSEMENT", Color.BLACK, 10, 460));
            control.getClassement().setClassementParticipants(control.getClassement().getDistancesParticipants(control.getCourse().getParticipants(), control.getCourse().getItineraire()));
            classement = control.getClassement().getClassementParticipants();
            pan.addDrawable(new StringDrawable("Premier : " + lesParticipants.get(classement.get(0)).getNomBateau(), lesCouleurs.get(classement.get(0)), 150, 460));
            pan.addDrawable(new StringDrawable("Deuxième : " + lesParticipants.get(classement.get(1)).getNomBateau(), lesCouleurs.get(classement.get(1)), 350, 460));
            pan.addDrawable(new StringDrawable("Troisième : " + lesParticipants.get(classement.get(2)).getNomBateau(), lesCouleurs.get(classement.get(2)), 550, 460));
        }
    }

    public final Panneau getPan() {
        return pan;
    }

    /**
     * Méthode qui permet d'afficher la fenetre.
     */
    public final void displayView(){
        this.setVisible(true);
    }

    /**
     * Méthode qui permet de ferme la fenetre
     */
    public final void closeView(){
        this.setVisible(false);
    }

    public final HashMap<Integer, Color> getLesCouleurs() {
        return lesCouleurs;
    }

    public final Controller getControl() {
        return control;
    }

    public final List getListeDate() {
        return listeDate;
    }

    /**
     * Méthode qui permet d'ajouter un texte à une position donnée.
     * @param couleur couleur du texte
     * @param x valeur de l'abscisse
     * @param y valeur de l'ordonnée
     * @param text texte à afficher
     */
    public final void addText(final Color couleur, final int x, final int y,
                              final String text) {
        pan.addDrawable(new StringDrawable(text, couleur, x, y));
        pan.repaint();
    }

    /**
     * Méthode qui permet de convertir une longitude en degré vers une valeur entière.
     * @param longitude valeur de la longitude en degré
     * @return valeur de la longitude en int
     */
    public final int ajusteLong(final int longitude){
        return (int) ((longitude + 180) * 950 / 360);
    }

    /**
     * Méthode qui permet de convertir une latitude en degré vers une valeur entière.
     * @param latitude valeur de la latitude en degré
     * @return valeur de la latitude en int
     */
    public final int ajusteLat(final int latitude){
        return (int) ((-latitude + 90) * 475 / 180);
    }
}
